package com.why.simpleboot.core.boot.starter;

import com.why.simpleboot.core.annotation.applicationcontext.ComponentScan;


import com.why.simpleboot.core.annotation.applicationcontext.EnableSimpleBootApplication;
import com.why.simpleboot.core.configration.ConfigurationFactory;
import com.why.simpleboot.core.configration.SimpleBootConfiguration;
import com.why.simpleboot.core.core.ApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;

/**
 * @program: why-simpleboot-framework
 * @description:
 * @author: @why  公共
 * @create: 2021-07-03 19:07
 **/
public abstract class AbstractSimpleBootStarter implements SimpleBootStarter {
    protected final Logger log = LoggerFactory.getLogger(AbstractSimpleBootStarter.class);
    /**
     * 实例化工厂
     */
    protected final ApplicationContext APPLICATION_CONTEXT = ApplicationContext.getAnnotationApplicationContext();
    /**
     * 默认需要扫描的包
     */
    protected final List<String> DEFAULT_SCAN_PACKAGES = new ArrayList<>();

    /*
     * 默认扫描异步任务执行器
     */ {
        DEFAULT_SCAN_PACKAGES.add("com.why.simpleboot.core.core.schedule.runner");
    }


    @Override
    public void initSimpleBoot(Class<?> clazz) {
//        加载配置文件
        log.info("start load config");
        SimpleBootConfiguration config = loadResources(clazz);
        log.info("Get start class location");
//        获取main方法启动的位置
        String startPosition = getStackTrace();
        startPosition = startPosition.substring(0, startPosition.lastIndexOf("."));
//将主启动类的位置也加入要扫描的包位置
        DEFAULT_SCAN_PACKAGES.add(startPosition);

//        判断启动类上面是否有@ComponentScan 有的话也扫描上
        if (clazz.isAnnotationPresent(ComponentScan.class)) {
            ComponentScan componentScan = clazz.getAnnotation(ComponentScan.class);
            DEFAULT_SCAN_PACKAGES.addAll(Arrays.asList(componentScan.value()));
        }
        log.info("The start class address is:{}", startPosition);
        log.info("server start ，init all bean...");
//        容器上下文的初始化
        APPLICATION_CONTEXT.init(DEFAULT_SCAN_PACKAGES, clazz);
        log.info("netty server starting...");
        log.info("startApplicationRunners...");
//        启动服务，服务启动完成后，执行所有的runner方法,因此需要参数package
        serverStart();
    }


    /**
     * 留给子类去实现，启动指定的服务器
     */
    protected abstract void serverStart();


    /**
     * 通过启动类的位置获取资源的路径，然后交给配置解析类去解析
     *
     * @param clazz
     */
    public SimpleBootConfiguration loadResources(Class<?> clazz) {
        SimpleBootConfiguration config = ConfigurationFactory.getConfig();
        ClassLoader classLoader = clazz.getClassLoader();
        ArrayList<Path> list = new ArrayList<>();

        //按照名字读取配置默认的配置文件，封装成url
        for (String fileName : config.getConfigNames()) {
            URL url = classLoader.getResource(fileName);
            if (Objects.nonNull(url)) {
                try {
                    Path path = Paths.get(url.toURI());
                    list.add(path);
                } catch (URISyntaxException e) {
                    e.printStackTrace();
                }

            }
        }
        config.loadResources(list);
        return config;
    }


    /**
     * StackTrace(堆栈轨迹)可以认为是一系列方法调用过程的集合。
     *
     * @return
     */
    private String getStackTrace() {
        StackTraceElement[] stack = new Throwable().getStackTrace();
        return stack[stack.length - 1].getClassName();

    }
}
